package com.hundsun.utils;

import com.alibaba.fastjson.JSON;
import com.hundsun.invocation.ConfigUsingInvocationHandler;
import com.hundsun.model.ExcelToDbData;
import com.hundsun.model.MappingConfigInfo;
import com.hundsun.model.interfaces.ConfigInfo;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @author jiangwj20966 2018/9/21
 */
public class ExcelInfoResolver {

    public List<ExcelToDbData> readFileInfo(File file, String excelFileName) {
        if (file != null) {
            try {
                XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(file));
                XSSFSheet sheet = workbook.getSheetAt(0);
                List<ExcelToDbData> dataList = new ArrayList<>();
                int start = sheet.getFirstRowNum();
                int end = sheet.getLastRowNum();
                for (int idx = start; idx <= end; idx++) {
                    dataList.add(convertRowToDataInfo(sheet.getRow(idx), excelFileName));
                }
                System.out.println(GsonFormatUtil.prettyJsonString(JSON.toJSONString(dataList)));
                return dataList;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将行数据信息转换为POJO
     *
     * @param row           excel行对象
     * @param excelFileName excel名称
     * @return 返回解析后的数据
     */
    private ExcelToDbData convertRowToDataInfo(XSSFRow row, String excelFileName) {
        ConfigInfo usingConfig = getUsingConfig(excelFileName);
        ExcelToDbData excelToDbData = new ExcelToDbData(usingConfig.getTableName());
        short lastNum = row.getLastCellNum();
        List<ExcelToDbData.DataInfo> dataInfoList = new ArrayList<>();
        ExcelToDbData.DataInfo dataInfo;
        for (short idx = row.getFirstCellNum(); idx <= lastNum; idx++) {
            dataInfo = new ExcelToDbData.DataInfo();
            dataInfo.setExcelColumnIndex(String.valueOf(idx));
            dataInfo.setColumnName(usingConfig.getColumnNameByExcelColumnIndex(dataInfo.getExcelColumnIndex()));
            if (StringUtils.isNotBlank(dataInfo.getColumnName())) {
                dataInfo.setValue(getCellValue(row.getCell(idx)));
                dataInfoList.add(dataInfo);
            }
        }
        excelToDbData.setExcelName(excelFileName);
        excelToDbData.setDataInfos(dataInfoList);
        excelToDbData.setTableName(usingConfig.getTableName());
        return excelToDbData;
    }

    private ConfigInfo getUsingConfig(String excelFileName) {
        MappingConfigInfo configInfo = ExcelToDbConfigParser.getInstance().getMappingConfigByExcelFile(excelFileName);
        if (configInfo == null) {
            throw new IllegalArgumentException(excelFileName + "对应的配置信息存在");
        }

        return (ConfigInfo) Proxy.newProxyInstance(configInfo.getClass().getClassLoader(),
                configInfo.getClass().getInterfaces(),
                new ConfigUsingInvocationHandler(configInfo));
    }


    private String getCellValue(Cell cell) {
        if (cell == null) {
            return null;
        }
        CellType cellType = cell.getCellTypeEnum();
        switch (cellType) {
            case _NONE:
            case BLANK:
            case ERROR:
                return "";
            case STRING:
                return cell.getStringCellValue();
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            case NUMERIC:
                double value = cell.getNumericCellValue();
                BigDecimal bigDecimal = new BigDecimal(value);
                return bigDecimal.toPlainString();
            default:
                System.out.println("neither");
                return null;
        }
    }
}
